package band.wukong.practice.webservice.kh.sample05;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;

import javax.xml.namespace.QName;
import javax.xml.soap.*;
import javax.xml.ws.handler.MessageContext;
import javax.xml.ws.handler.soap.SOAPHandler;
import javax.xml.ws.handler.soap.SOAPMessageContext;
import javax.xml.ws.soap.SOAPFaultException;
import java.util.HashSet;
import java.util.Set;

/**
 * Lisence handler.
 * VIDEO-21, 为了鉴权费查询的操作。
 *
 * @author wukong(wukonggg@139.com)
 */
public class JukeboxServerHeaderHandler implements SOAPHandler<SOAPMessageContext> {

    private final Logger logger = LoggerFactory.getLogger(JukeboxServerHeaderHandler.class);

    /**
     * Operations need be auth in wsdl/Service
     */
    private static final HashSet<String> OPS_NEED_AUTH;

    static {
        OPS_NEED_AUTH = new HashSet<>();
//        OPS_NEED_AUTH.add("addArtist");
//        OPS_NEED_AUTH.add("updateArtist");
        OPS_NEED_AUTH.add("removeArtist");
    }

    private int counter = 0;


    @Override
    public Set<QName> getHeaders() {
        return null;
    }

    @Override
    public boolean handleMessage(SOAPMessageContext context) {
        logger.debug("[Server][Handler] handleMessage");

        // 对于server，如果out是true，说明消息是要发送出去的，不需要处理header；
        // 对于server，如果out是false，说明消息是接收进来的，需要处理header。
        Boolean out = (Boolean) context.get(MessageContext.MESSAGE_OUTBOUND_PROPERTY);
        if (!out) {
            handleHeaderOfInboundMessage(context);
        }
        return true;
    }

    private void handleHeaderOfInboundMessage(SOAPMessageContext context) {
        SOAPMessage message = context.getMessage();
        try {
            SOAPEnvelope envelope = message.getSOAPPart().getEnvelope();
            SOAPBody body = envelope.getBody();

            Node bn = body.getChildNodes().item(0);
            String partName = bn.getLocalName();
            logger.debug("[Server][Handler] partName = " + partName);

            // 当非查询类操作时，需要校验权限，处理头信息。
            if (null == partName || "".equals(partName.trim())) {
                logger.debug("[Server][Handler] Invalid part name: " + partName);
            } else if (OPS_NEED_AUTH.contains(partName)) {
                logger.debug("[Server][Handler] Need auth. ");
                SOAPHeader header = envelope.getHeader();
                handleHeaderOfInboundMessageDetail(header, body);
            } else {
                logger.debug("[Server][Handler] Don't need auth. ");
            }

        } catch (SOAPException e) {
            e.printStackTrace();
        }

    }

    private void handleHeaderOfInboundMessageDetail(SOAPHeader header, SOAPBody body) throws SOAPException {
        if (null == header || !header.extractAllHeaderElements().hasNext()) {
            logger.warn("校验未通过" + ++counter);
            SOAPFault fault = body.addFault();
            fault.setFaultCode("ERR_1");
            fault.setFaultString("没有找到header信息");
            throw new SOAPFaultException(fault);
        } else {
            try {
                NodeList nodeList = header.getElementsByTagName("ns:licenseInfo");
                Node node = nodeList.item(0);
                logger.debug("[Server][Handler] licenseInfo: " + node.getTextContent());
            } catch (NullPointerException e) {
                logger.warn("校验未通过" + ++counter);
                SOAPFault fault = body.addFault();
                fault.setFaultCode("ERR_2");
                fault.setFaultString("没有找到有效的header信息");
                throw new SOAPFaultException(fault);
            }
        }
    }

    @Override
    public boolean handleFault(SOAPMessageContext context) {
        logger.debug("[Server][Handler] handleFault");
        return false;
    }

    @Override
    public void close(MessageContext context) {
        logger.debug("[Server][Handler] close");
    }
}
